﻿//Copyright (c) 2010 Christopher E. S. King (http://chriskingconsulting.com)
//
//Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 
// (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do 
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Linq;

using King.Text;

namespace King.TeamFoundation {

    public class VSString : TextNodes {

        #region Constructor
        public VSString() { }
        public VSString(params object[] values) {
            Add(values);
        }
        #endregion

        #region TextNode Overrides
        protected override IEnumerable<object> Content(TextNodeContext context) {
            return ArbitraryContent;
        }
        protected override IEnumerable<object> Children(TextNodeContext context) {
            return new TextNodes() {
                "\"", Children(), "\""
            };
        }
        #endregion
    }
    public class VSSection : TextNodes {

        #region Private Data Members
        private object m_key;
        private object m_argument;
        private object m_value;
        #endregion

        #region Constructor
        public VSSection(object key, object argument, object value) {
            m_key = key;
            m_argument = argument;
            m_value = value;
        }
        #endregion

        #region TextNode Overrides
        protected override IEnumerable<object> Content(TextNodeContext context) {
            return ArbitraryContent;
        }
        protected override IEnumerable<object> Children(TextNodeContext context) {
            return new TextSingleSpaced() {
                new TextNodes() {
                    m_key, "(", m_argument, ") = ", m_value
                },
                new TextIndent("\t") {
                    new TextSingleSpaced() {
                        Children()
                    }
                },
                new TextNodes() {
                    "End", m_key
                }
            };
        }
        #endregion
    }
    public class VSSectionItem : TextNode {

        private object m_lhs;
        private object m_rhs;

        public VSSectionItem(object item) {
            m_lhs = m_rhs = item;
        }
        public VSSectionItem(object lhs, object rhs) {
            m_lhs = lhs;
            m_rhs = rhs;
        }

        protected override IEnumerable<object> Content(TextNodeContext context) {
            return ArbitraryContent;
        }
        protected override IEnumerable<object> Children(TextNodeContext context) {
            return new TextNodes() { m_lhs, " = ", m_rhs };
        }
    }
    public class VSGuid : TextNode {
        private Guid m_guid;

        public VSGuid(Guid guid) {
            m_guid = guid;
        }

        protected override IEnumerable<object> Content(TextNodeContext context) {
            return ArbitraryContent;
        }
        protected override IEnumerable<object> Children(TextNodeContext context) {
            return new[] { "{" + m_guid.ToString().ToUpper() + "}" };
        }
    }

    public class VSProject : TextNodes {

        #region Private Data Members
        private object m_typeGuid;
        private object m_idGuid;
        private object m_name;
        private object m_path;
        #endregion

        #region Constructor
        public VSProject(object typeGuid, object idGuid, object name, object path) {
            m_idGuid = idGuid;
            m_typeGuid = typeGuid;
            m_name = name;
            m_path = path;
        }
        #endregion

        #region TextNode Overrides
        protected override IEnumerable<object> Content(TextNodeContext context) {
            return ArbitraryContent;
        }
        protected override IEnumerable<object> Children(TextNodeContext context) {
            return new VSSection("Project", new VSString(m_typeGuid), new TextJoin(", ") {
                new VSString(m_name), new VSString(m_path), new VSString(m_idGuid)
            }) {
               Children()
            };
        }
        #endregion
    }
    public class VSProjectDependencies : TextNodes {

        #region TextNode Overrides
        protected override IEnumerable<object> Content(TextNodeContext context) {
            return Children();
        }
        protected override IEnumerable<object> Children(TextNodeContext context) {
            return new VSSection("ProjectSection", "ProjectDependencies", "postProject") {
                    from o in context.Flatten(Children())
                    select new TextNodes() { o, " = ", o }
            };
        }
        #endregion
    }
    public class VSCXProject : VSProject {

        #region Static Public Members
        public static Guid Guid = new Guid("8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942");
        #endregion

        #region Constructor
        public VSCXProject(object idGuid, object name, object path)
            : base(Guid, idGuid, name, path) {
        }
        #endregion
    }
    public class VSCSharpProject : VSProject {

        #region Static Public Members
        public static Guid Guid = new Guid("FAE04EC0-301F-11D3-BF4B-00C04F79EFBC");
        #endregion

        #region Constructor
        public VSCSharpProject(object idGuid, object name, object path)
            : base(Guid, idGuid, name, path) {
        }
        #endregion
    }

    public class VSSolutionFolder : TextNodes {

        #region Static Public Members
        public static Guid ProjectTypeGuid = new Guid("2150E333-8FDC-42A3-9474-1A3956D46DE8");
        #endregion

        #region Constructor
        public VSSolutionFolder() {
        }
        public VSSolutionFolder(object guid, object name) {
            Guid = guid;
            Name = name;
        }
        #endregion

        #region TextNode Overrides
        protected override IEnumerable<object> Content(TextNodeContext context) {
            return ArbitraryContent;
        }
        protected override IEnumerable<object> Children(TextNodeContext context) {
            return new VSProject(ProjectTypeGuid, Guid, Name, Name) {
                Children()
            };
        }
        #endregion

        #region Public Members
        public object Name { get; set; }
        public object Guid { get; set; }
        #endregion
    }
    public class VSSolutionItems : TextNodes {

        #region TextNode Overrides
        protected override IEnumerable<object> Content(TextNodeContext context) {
            return Children();
        }
        protected override IEnumerable<object> Children(TextNodeContext context) {
            return new VSSection("ProjectSection", "SolutionItems", "preProject") {
                new TextSingleSpaced() {
                    Children().Select(o => o + " = " + o)
                }
            };
        }
        #endregion
    }

    public class VSSolution : TextNode {

        #region TextNode Overrides
        protected override IEnumerable<object> Content(TextNodeContext context) {
            return ArbitraryContent;
        }
        protected override IEnumerable<object> Children(TextNodeContext context) {
            return new TextSingleSpaced() {
                string.Empty,
                new TextNodes() { "Microsoft Visual Studio Solution File, Format Version ", Version },
                //"Microsoft Visual Studio Solution File, Format Version 11.00",
                new TextNodes() { "# Visual Studio ", Year },
                Projects,
                "Global", new TextIndent("\t") {
                    new TextSingleSpaced() {
                        Global
                    }
                }, "EndGlobal"
            };
        }
        protected override IEnumerable<object> Substitute(TextNodeContext context, object value) {
            if (value is Guid)
                yield return new VSGuid((Guid)value);
            else
                yield return value;
        }
        #endregion

        #region Public Members
        public object Projects { get; set; }
        public object Global { get; set; }
        public object Version { get; set; }
        public object Year { get; set; }
        #endregion
    }
    public class VSSolutionConfigurations : TextNodes {

        #region TextNode Overrides
        protected override IEnumerable<object> Content(TextNodeContext context) {
            return ArbitraryContent;
        }
        protected override IEnumerable<object> Children(TextNodeContext context) {
            return new VSSection("GlobalSection", "SolutionConfigurationPlatforms", "preSolution") {
                context.Flatten(Children()).Select(o => new TextJoin(" ") { o, "=", o })
            };
        }
        #endregion
    }
    public class VSProjectConfigurations : TextNodes {

        #region TextNode Overrides
        protected override IEnumerable<object> Content(TextNodeContext context) {
            return ArbitraryContent;
        }
        protected override IEnumerable<object> Children(TextNodeContext context) {
            return new VSSection("GlobalSection", "ProjectConfigurationPlatforms", "postSolution") {
                Children()
            };
        }
        #endregion
    }
    public class VSProjectConfiguration : TextNode {

        public VSProjectConfiguration(object projectGuid, object solutionConfiguration, object projectConfiguration, bool isEnabled) {
            ProjectGuid = projectGuid;
            ProjectConfiguration = projectConfiguration;
            SolutionConfiguration = solutionConfiguration;
            IsEnabled = isEnabled;
        }

        private string GetConfiguration(object o) {
            var s = new TextNodes() { o }.ReadToEnd();
            return s.Replace("AnyCPU", "Any CPU");
        }
        private object GetConfiguration(bool isEnabled) {
            var active = isEnabled ? "Build.0" : "ActiveCfg";
            return new TextNodes() { 
                ProjectGuid, ".", 
                GetConfiguration(SolutionConfiguration), ".", 
                active, " = ", 
                GetConfiguration(ProjectConfiguration)
            };
        }

        protected override IEnumerable<object> Content(TextNodeContext context) {
            return ArbitraryContent;
        }
        protected override IEnumerable<object> Children(TextNodeContext context) {
            return new TextSingleSpaced() {
                GetConfiguration(false),
                IsEnabled ? GetConfiguration(true) : null,
            };
        }

        public object ProjectGuid { get; set; }
        public object ProjectConfiguration { get; set; }
        public object SolutionConfiguration { get; set; }
        public bool IsEnabled { get; set; }
    }

    public class VSSolutionProperties : TextNode {

        #region TextNode Overrides
        protected override IEnumerable<object> Content(TextNodeContext context) {
            return ArbitraryContent;
        }
        protected override IEnumerable<object> Children(TextNodeContext context) {
            return new VSSection("GlobalSection", "SolutionProperties", "preSolution") {
                "HideSolutionNode = " + (HideSolutionNode ? "TRUE" : "FALSE")
            };
        }
        #endregion

        #region Public Members
        public bool HideSolutionNode { get; set; }
        #endregion
    }
    public class VSNestedProjects : TextNodes {

        #region TextNode Overrides
        protected override IEnumerable<object> Content(TextNodeContext context) {
            return Children();
        }
        protected override IEnumerable<object> Children(TextNodeContext context) {
            return new VSSection("GlobalSection", "NestedProjects", "preSolution") {
                Children()
            };
        }
        #endregion
    }
    public class VSNestedProject : TextNode {

        #region Constructor
        public VSNestedProject(object enclosingProjectGuid, object projectGuid) {
            EnclosingProjectGuid = enclosingProjectGuid;
            ProjectGuid = projectGuid;
        }
        #endregion

        #region TextNode Overrides
        protected override IEnumerable<object> Content(TextNodeContext context) {
            return ArbitraryContent;
        }
        protected override IEnumerable<object> Children(TextNodeContext context) {
            return new TextNodes() { ProjectGuid, " = ", EnclosingProjectGuid };
        }
        #endregion

        #region Public Members
        public object EnclosingProjectGuid { get; set; }
        public object ProjectGuid { get; set; }
        #endregion
    }

    public class CmdLineArg : TextNode {

        private object m_argument;

        public CmdLineArg(object argument) {
            m_argument = argument;
        }

        protected override IEnumerable<object> Children(TextNodeContext context) {
            if (m_argument is string && !((string)m_argument).Contains(' '))
                return new[] { m_argument };

            return new TextNodes() { "\"", m_argument, "\"" };
        }
    }
    public class TCommandLineArgument : TextNodes {

        protected override IEnumerable<object> Children(TextNodeContext context) {
            throw new NotImplementedException();
            //var argument = ToString(context, Content());
            //if (Regex.IsMatch(argument, @"[\s|""]"))
            //    argument = "\"" + argument.Replace("\"", "\\\"") + "\"";
            //yield return argument;
        }
    }
}
